package com.beta.cat.utils.http;

import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

/**
 * HTTP连接配置，包括连接池和代理配置
 *
 * @author gwqin
 * @description HTTP连接配置
 * @date 2022-09-19 19:38
 */
public class HttpConfig {

    /**
     * 连接池最大连接数
     * 建议：maxConnectionSizeTotal = 瞬时最大并发数总和 * 1.2
     * 例：用户服务总共调用 A、B、C 三个域名请求，A、B、C 瞬时最大并发数总和为 150 = (A：80 + B：20 + C：50)
     * 则 maxConnectionSizeTotal = 150 * 1.2 = 180
     */
    private int maxConnectionSizeTotal = 300;

    /**
     * 每个主机/域名最大连接数
     * 建议：maxConnectionSizePerRoute = 单个主机/域名瞬时最大并发数 * 1.2
     * 例：用户服务总共调用 A、B、C 三个域名请求，A、B、C 瞬时最大并发数分别为80、20、50
     * 则 maxConnectionSizePerRoute = 80 * 1.2 = 96
     */
    private int maxConnectionSizePerRoute = 100;

    /**
     * HTTP代理配置
     */
    private HttpProxy httpProxy;

    public int getMaxConnectionSizeTotal() {
        return maxConnectionSizeTotal;
    }

    public HttpConfig setMaxConnectionSizeTotal(int maxConnectionSizeTotal) {
        this.maxConnectionSizeTotal = maxConnectionSizeTotal;
        return this;
    }

    public int getMaxConnectionSizePerRoute() {
        return maxConnectionSizePerRoute;
    }

    public HttpConfig setMaxConnectionSizePerRoute(int maxConnectionSizePerRoute) {
        this.maxConnectionSizePerRoute = maxConnectionSizePerRoute;
        return this;
    }

    public HttpProxy getHttpProxy() {
        return httpProxy;
    }

    /**
     * 设置http代理
     *
     * @param httpProxyHost 代理主机名
     * @param httpProxyPort 代理主机端口
     */
    public HttpConfig setHttpProxy(String httpProxyHost, Integer httpProxyPort) {
        HttpProxy proxy = new HttpProxy()
                .setHttpProxyHost(httpProxyHost)
                .setHttpProxyPort(httpProxyPort);
        this.httpProxy = proxy;
        return this;
    }

    /**
     * 设置http代理
     *
     * @param httpProxyHost 代理主机名
     * @param httpProxyPort 代理主机端口
     * @param userName 登录凭证-用户名
     * @param password 登录凭证-密码
     */
    public HttpConfig setHttpProxy(String httpProxyHost, Integer httpProxyPort, String userName, String password) {
        HttpProxy proxy = new HttpProxy()
                .setHttpProxyHost(httpProxyHost)
                .setHttpProxyPort(httpProxyPort)
                .setUserName(userName)
                .setPassword(password);
        this.httpProxy = proxy;
        return this;
    }

    /**
     * HTTP代理
     */
    class HttpProxy {

        /**
         * 代理主机名
         */
        private String httpProxyHost;

        /**
         * 代理端口
         */
        private Integer httpProxyPort;

        /**
         * 登录凭证-用户名
         */
        private String userName;

        /**
         * 登录凭证-密码
         */
        private String password;

        public String getHttpProxyHost() {
            return httpProxyHost;
        }

        public HttpProxy setHttpProxyHost(String httpProxyHost) {
            if (httpProxyHost == null || httpProxyHost.trim().length() == 0) {
                throw new IllegalArgumentException("invalid httpProxyHost value!");
            }
            this.httpProxyHost = httpProxyHost;
            return this;
        }

        public Integer getHttpProxyPort() {
            return httpProxyPort;
        }

        public HttpProxy setHttpProxyPort(Integer httpProxyPort) {
            if (httpProxyPort == null || httpProxyPort.intValue() < 1) {
                throw new IllegalArgumentException("invalid httpProxyPort value!");
            }
            this.httpProxyPort = httpProxyPort;
            return this;
        }

        public String getUserName() {
            return userName;
        }

        public HttpProxy setUserName(String userName) {
            if (userName == null || userName.trim().length() == 0) {
                throw new IllegalArgumentException("invalid userName value!");
            }
            this.userName = userName;
            return this;
        }

        public String getPassword() {
            return password;
        }

        public HttpProxy setPassword(String password) {
            if (password == null || password.trim().length() == 0) {
                throw new IllegalArgumentException("invalid password value!");
            }
            this.password = password;
            return this;
        }

        @Override
        public String toString() {
            return "HttpProxy{" +
                    "httpProxyHost='" + httpProxyHost + '\'' +
                    ", httpProxyPort=" + httpProxyPort +
                    ", userName='" + userName + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }

    @Override
    public String toString() {
        return "HttpConfig{" +
                "maxConnectionSizeTotal=" + maxConnectionSizeTotal +
                ", maxConnectionSizePerRoute=" + maxConnectionSizePerRoute +
                ", httpProxy=" + (httpProxy == null ? "null" : httpProxy.toString()) +
                '}';
    }

    /**
     * 生成配置信息的摘要，用于缓存RestTemplate实例时，作为RestTemplate实例的key。
     * 生成摘要的目的是为了缩短key的长度。
     * RestTemplateUtil会根据key从内存获取已经存在的RestTemplate实例。
     *
     * @return
     */
    public String getKey() {
        String key = this.toString();
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            byte[] digestBytes = messageDigest.digest(key.getBytes(StandardCharsets.UTF_8));
            key = DatatypeConverter.printHexBinary(digestBytes);
        } catch (Exception ignore) {
            // 此处异常无需处理，当出现异常时直接返回this.toString()对工具功能无任何影响
        }
        return key;
    }
}
